import re

def build_url(url):
    url, num = re.subn(r'\bpage=[^&]*', 'page={0}', url)
    if num == 0:
        url = url + ('?' if url.find('?') == -1 else '&') + 'page={0}'
    return url

def paginate(q, page, page_size=20):
    return q[(page-1)*page_size : page*page_size]


class Paginator(list):
    def __init__(self, q, page, page_size=20, count=None, url='', is_paged=False):
        if page < 1:
            page = 1
        self.page = page
        self.page_size = page_size
        self.count = q.count() if count is None else count
        self.url = url
        super(Paginator, self).__init__(q if is_paged else q[(page-1)*page_size : page*page_size])

    @property
    def paging_links(self):
        url = build_url(self.url)
        return paging_links(url, self.count, self.page, self.page_size)


class SimplePaginator(list):
    def __init__(self, q, page, page_size=20, has_next=True, url='', is_paged=False):
        if page < 1:
            page = 1
        self.page = page
        self.page_size = page_size
        items = q if is_paged else q[(page-1)*page_size : page*page_size]
        self.has_next = has_next and len(items) == page_size
        self.url = url
        super(SimplePaginator, self).__init__(items)

    @property
    def paging_links(self):
        url = build_url(self.url)
        return paging_simple_links(url, self.has_next, self.page, self.page_size)


def paging_simple_links(url, has_next, cur_page=1, page_size=20):
    num_pages = cur_page + 1 if has_next else cur_page
    if num_pages <= 1:
        return ''

    output = ['<div class="paginator">']

    def link(page, text=None):
        if page != cur_page:
            output.append('<a href="{0}">{1}</a>'.format(url.format(page), text or page))
        else:
            output.append('<span class="current">{0}</span> '.format(text or page))
    
    link(max(cur_page - 1, 1), '上一页')
    link(1)

    if cur_page - 2 > 2:
        output.append('...')

    for i in range(max(2, cur_page - 2), min(num_pages - 1, cur_page + 2) + 1):
        link(i)

    if cur_page + 2 < num_pages - 1:
        output.append('...')

    if num_pages > 1:
        link(num_pages)

    link(min(cur_page + 1, num_pages), '下一页')
    output.append('</div>')

    return ' '.join(output)


def paging_links(url, count, cur_page=1, page_size=20):
    if count % page_size == 0:
        num_pages = count // page_size
    else:
        num_pages = count // page_size + 1

    if num_pages <= 1:
        return ''

    if cur_page > num_pages: 
        cur_page = num_pages
    if cur_page < 1:
        cur_page = 1

    output = ['<div class="paginator">']

    def link(page, text=None):
        if page != cur_page:
            output.append('<a href="{0}">{1}</a>'.format(url.format(page), text or page))
        else:
            output.append('<span class="current">{0}</span> '.format(text or page))
    
    link(max(cur_page - 1, 1), '上一页')
    link(1)

    if cur_page - 2 > 2:
        output.append('...')

    for i in range(max(2, cur_page - 2), min(num_pages - 1, cur_page + 2) + 1):
        link(i)

    if cur_page + 2 < num_pages - 1:
        output.append('...')

    if num_pages > 1:
        link(num_pages)

    link(min(cur_page + 1, num_pages), '下一页')
    output.append('</div>')

    return ' '.join(output)

